home *** CD-ROM | disk | FTP | other *** search
- #include "palette.hpp"
- #include "image.hpp"
- #include "macs.hpp"
- #include "dos.h"
- #include "video.hpp"
- #include "filter.hpp"
- #include "jmalloc.hpp"
- #include <math.h>
-
- palette *lastl=NULL;
-
- palette::palette(bFILE *fp)
- {
- ncolors=fp->read_short();
- pal=(color *)jmalloc(sizeof(color)*ncolors,"palette");
- usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
- set_all_unused();
- fp->read(pal,sizeof(color)*ncolors);
- bg=0;
- }
-
- palette::palette(spec_entry *e, bFILE *fp)
- {
- fp->seek(e->offset,0);
- ncolors=fp->read_short();
- pal=(color *)jmalloc(sizeof(color)*ncolors,"palette");
- usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
- set_all_unused();
- fp->read(pal,sizeof(color)*ncolors);
- bg=0;
- }
-
- int palette::size()
- {
- return ncolors*sizeof(color)+2;
- }
-
- int palette::write(bFILE *fp)
- {
- fp->write_short(ncolors);
- return fp->write(pal,sizeof(color)*ncolors)==ncolors;
- }
-
- int palette::find_closest(unsigned char r, unsigned char g, unsigned char b)
- {
- unsigned char *cl=(unsigned char *)addr();
- int c=0,d=0x100000,i,nd;
- for (i=0;i<256;i++)
- {
- nd=((int)r-(int)(*cl))*((int)r-(int)(*cl)); cl++;
- nd+=((int)g-(int)(*cl))*((int)g-(int)(*cl)); cl++;
- nd+=((int)b-(int)(*cl))*((int)b-(int)(*cl)); cl++;
- if (nd<d)
- { c=i; d=nd; }
- }
- return c;
- }
-
-
- int palette::find_closest_non0(unsigned char r, unsigned char g, unsigned char b)
- {
- unsigned char *cl=(unsigned char *)addr()+3;
- int c=1,d=0x7fffffff,i,nd;
- for (i=1;i<256;i++)
- {
- nd=((int)r-(int)(*cl))*((int)r-(int)(*cl)); cl++;
- nd+=((int)g-(int)(*cl))*((int)g-(int)(*cl)); cl++;
- nd+=((int)b-(int)(*cl))*((int)b-(int)(*cl)); cl++;
- if (nd<d)
- { c=i; d=nd; }
- }
- return c;
- }
-
-
- int palette::find_color(unsigned char r, unsigned char g, unsigned char b)
- {
- int i,ub,mask,find;
- for (i=0,ub=0,mask=128,find=-1;i<ncolors && find<0;i++)
- {
- if (usd[ub]&mask)
- if (r==pal[i].red && b==pal[i].blue && g==pal[i].green)
- find=i;
- mask>>=1;
- if (mask==0)
- { mask=128; ub++; }
- }
- return find;
- }
-
- long palette::getquad(int x)
- { char entry[4];
- entry[3]=0;
- entry[2]=pal[x].red;
- entry[1]=pal[x].green;
- entry[0]=pal[x].blue;
- return *((long *)entry);
- }
-
-
- void palette::black_white()
- {
- int i;
- unsigned char r,g,b,gr;
-
- for (i=0;i<256;i++)
- {
- get(i,r,g,b);
- gr=(unsigned char)((double) r*0.30+(double) g*0.59+(double)b*0.11);
- set(i,gr,gr,gr);
- }
- }
-
- void palette::make_black_white()
- {
- int i,c;
- set(0,0,0,0);
- for (i=1;i<ncolors;i++)
- { c=(int)((double)i/(double)ncolors*(double)255);
- set(i,c,c,c);
- }
- }
-
- void palette::set_rgbs()
- {
- int i,v;
- CHECK(ncolors==256);
- for (i=0;i<64;i++)
- {
- if (i==0) v=0;
- else
- {
- v=(int) ((double)i+(double)(sqrt(63-i)));
- v<<=2;
- }
-
- set(i, i, 0, 0); // reds 0-63
- set(i+64, 0, i, 0);
- set(i+128, 0, 0, i); // blues 128-191
- set(i+128+64, v, v, v); // whites .. rest
- }
- set_all_used();
- }
-
- void palette::set_all_used()
- {
- int i;
- for (i=0;i<ncolors;i++) set_used(i);
- }
-
- void palette::set_all_unused()
- {
- int i;
- for (i=0;i<ncolors;i++) set_unused(i);
- }
-
-
- palette *palette::copy()
- {
- palette *p;
- int i;
- p=new palette(ncolors);
- for (i=0;i<ncolors;i++)
- {
- if (used(i))
- p->set_used(i);
- else p->set_unused(i);
- p->set(i,red(i),green(i),blue(i));
- }
- return p;
- }
-
- void palette::set_used(int color_num)
- {
- int x,b;
- CHECK(color_num>=0 && color_num<ncolors);
- x=color_num/8;
- b=color_num%8;
- usd[x]|=(128>>b);
- }
-
- void palette::set_unused(int color_num)
- {
- int x,b;
- CHECK(color_num>=0 && color_num<ncolors);
- x=color_num/8;
- b=color_num%8;
- usd[x]&=(0xff^(128>>b));
- }
-
- int palette::used(int color_num)
- {
- int x,b;
- CHECK(color_num>=0 && color_num<ncolors);
- x=color_num/8;
- b=color_num%8;
- return (usd[x]&(128>>b));
- }
-
- int palette::add_color(unsigned int r, int unsigned g, int unsigned b, int closest_only)
- {
- int i,f,u,c;
- if (!closest_only)
- {
- for (i=ncolors-1,f=-1,u=-1;i>=0 && f<0;i--)
- {
- if (used(i))
- {
- if (pal[i].red==r && pal[i].green==g && pal[i].blue==b)
- f=i;
- }
- else
- u=i;
- }
- } else { f=-1; u=-1; }
- if (f<0)
- {
- if (u>=0)
- { pal[u].red=r;
- pal[u].green=g;
- pal[u].blue=b;
- set_used(u);
- f=u;
- }
- else
- {
- for (i=0,f=0,u=10000;i<ncolors;i++)
- { c=(pal[i].red-r)*(pal[i].red-r)+
- (pal[i].green-g)*(pal[i].green-g)+
- (pal[i].blue-b)*(pal[i].blue-b);
- if (c<u)
- { f=i;
- u=c;
- }
- }
- }
- }
- return f;
- }
-
- void palette::defaults()
- {
- int i;
- set(0,0,0,0);
- set_used(0);
- for (i=1;i<ncolors;i++)
- set_unused(i);
- if (ncolors==256)
- for (i=0;i<ncolors;i++)
- set(i,RED3(i),GREEN3(i),BLUE2(i));
- else if (ncolors==16)
- for (i=0;i<ncolors;i++)
- set(i,255-i&3,255-(i&4)>>2,255-(i&8)>>3);
- else
- for (i=0;i<ncolors;i++)
- set(i,255-i%3,255-(i+1)%3,255-(i+2)%3);
- }
-
- void palette::shift(int amount)
- {
- int i;
- unsigned char m;
- if (amount<0)
- {
-
- m=-amount;
- for (i=0;i<ncolors*3;i++)
- ((unsigned char *) pal)[i]>>=m;
- }
- else if (amount>0)
- {
- m=amount;
- for (i=0;i<ncolors*3;i++)
- ((unsigned char *) pal)[i]<<=m;
- }
- }
-
-
-
- void palette::set(int x, unsigned char red, char unsigned green, char unsigned blue)
- { CONDITION(x>=0 && x<ncolors,"Pallete::set passed bad x");
- CONDITION((int)red<=ncolors && (int)green<=ncolors && (int)blue<=ncolors,
- "pallette::set color values bigger than palette");
- pal[x].red=red; pal[x].green=green; pal[x].blue=blue;
- }
-
- void palette::get(int x, unsigned char &red, unsigned char &green, unsigned char &blue)
- { CONDITION(x>=0 && x<ncolors,"Pallete::get passed bad x");
- red=pal[x].red; green=pal[x].green; blue=pal[x].blue;
- }
- palette::~palette()
- { if (pal) jfree(pal);
- if (usd) jfree(usd);
- }
-
- palette::palette(int number_colors)
- {
- CONDITION(number_colors>0,"palette::constructor - need at least one color!");
- ncolors=number_colors;
- bg=0;
- pal=(color *)jmalloc(ncolors*3,"palette");
- usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
- defaults();
- }
-
-
-
- quant_node::~quant_node()
- {
- /* if (!is_leaf())
- { for (i=0;i<8;i++)
- if (children[i])
- { delete children[i];
- children[i]=NULL;
- }
- } */
- }
-
-
- /*void quant_node::prune()
- {
- int t,r,g,b;
- CONDITION(!is_leaf(),"Cannot prune a leaf!");
- total(t,r,g,b);
- red=r/t;
- green=g/t;
- blue=b/t;
- be_childish();
- } */
-
- void quant_node::total(int &tnodes, int &tr, int &tg, int &tb)
- {
- int i;
- if (is_leaf())
- { tnodes+=tot;
- tr+=red*tot;
- tg+=green*tot;
- tb+=blue*tot;
- }
- else
- { for (i=0;i<8;i++)
- if (children[i])
- children[i]->total(tnodes,tr,tg,tb);
- }
- }
-
- quant_node::quant_node(int level, quant_node *dad,
- unsigned char r, unsigned char g, unsigned char b)
- {
- int i;
- CONDITION(level<=8,"Tree cannot have more than eight levels");
- if (level==8)
- be_childish();
- else
- for (i=0;i<8;i++) children[i]=NULL;
- padre=dad;
- red=r; green=g; blue=b;
- tot=0;
- }
-
- quant_palette::quant_palette(int max_colors)
- { root=NULL; nc=0; mx=max_colors; }
-
- void quant_palette::re_delete(quant_node *who, int lev) // removes all children from memory
- { int x; // and recurses down
- if (who)
- {
- if (!who->is_leaf())
- { for (x=0;x<8;x++)
- if (who->children[x])
- {
- CONDITION(lev<8,"Levl > 7");
- re_delete(who->children[x],lev+1);
- level[lev].unlink((linked_node *)who->children[x]);
- delete who->children[x];
- }
- }
- }
- }
-
- void quant_palette::prune()
- {
- int pruned,lev,x,r,g,b,t;
- quant_node *p,*f;
- for (pruned=0,lev=8;lev>1 && !pruned;lev--)
- {
- p=(quant_node *)level[lev-1].first();
- if (p)
- { do
- {
- f=p->father();
- for (x=0;x<8 && !pruned;x++)
- if (f->children[x])
- if (f->children[x]->next()!=p->next()) // if this son is not me!
- pruned=1; // I have a brother! stop
- p=(quant_node *)p->next();
- } while ((linked_node *) p!=level[lev-1].first() && !pruned);
- }
- }
- CONDITION(lev>0,"could not prune!");
- t=0; r=0; g=0; b=0;
- f->total(t,r,g,b);
- if (t<=1)
- {
- t=0; r=0; g=0; b=0;
- f->total(t,r,g,b);
- }
- CONDITION(t>1,"Should be more colors\n");
- printf("%d Pruned at level %d, r=%d, g=%d, b=%d, total nodes off = %d\n",nc,
- lev,r/t,g/t,b/t,t);
- f->set(r/t,g/t,b/t);
- nc-=t;
- nc++;
- re_delete(f,lev);
- f->be_childish();
- }
-
- void quant_palette::add_color(unsigned char r, unsigned char g, unsigned char b)
- {
- quant_node **p,*fat;
- int lev,cn,stop;
- p=&root;
- lev=0;
- stop=0;
- fat=NULL;
- if (nc>=mx-1)
- prune();
- while (!stop)
- {
- lev++;
- if (!(*p))
- {
- if (lev>2 && !fat)
- printf("h");
- (*p)=new quant_node(lev,fat);
- level[lev-1].add_end((linked_node *)(*p));
- }
-
- if (!(*p)->is_leaf())
- {
- cn=((r&(256>>lev))!=0)<<2;
- cn+=((g&(256>>lev))!=0)<<1;
- cn+=((b&(256>>lev))!=0);
- fat=(*p);
- p=&((*p)->children[cn]);
- } else stop=1;
-
- }
- (*p)->set(r,g,b);
- if (!(*p)->tot)
- nc++;
- (*p)->tot++;
- }
-
- palette *quant_palette::create_pal()
- {
- palette *p;
- int i,x;
- quant_node *pn;
- p=new palette(mx);
- for (x=0,i=7;i>=0;i++)
- for (pn=(quant_node *)level[i].first();
- pn!=(quant_node *)level[i].first();pn=(quant_node *)pn->next())
- if (pn->is_leaf())
- p->set(x++,pn->red,pn->green,pn->blue);
- return p;
- }
-
- quant_palette::~quant_palette()
- {
- if (root)
- {
- re_delete(root,1);
- delete root;
- }
- }
-
- unsigned char palette::brightest(int all)
- { unsigned char r,g,b,bri;
- unsigned i;
- long brv;
- brv=0; bri=0;
-
- for (i=0;i<ncolors;i++)
- { if (all || used(i))
- {
- get(i,r,g,b);
- if ((long)r*(long)g*(long)b>brv)
- { brv=(long)r*(long)g*(long)b;
- bri=i;
- }
- }
- }
-
- return bri;
- }
-
- unsigned char palette::darkest(int all, int noblack)
- { unsigned char r,g,b,bri;
- unsigned i;
- long brv,x;
- brv=(long)258*(long)258*(long)258; bri=0;
-
- for (i=0;i<ncolors;i++)
- { if (all || used(i))
- {
- get(i,r,g,b);
- x=(long)r*(long)g*(long)b;
- if (x<brv && (x || !noblack))
- { brv=(long)r*(long)g*(long)b;
- bri=i;
- }
- }
- }
- return bri;
- }
-
-
-
- palette *last_loaded()
- { return lastl; }
-
- void palette::fade_to(int total_fades, int fade_on, int dest_r, int dest_g, int dest_b)
- {
- unsigned char *sl=(unsigned char *)addr();
- int i;
- for (i=0;i<ncolors;i++)
- {
- *(sl++)=(( dest_r-(int)*sl)*fade_on/total_fades+*sl);
- *(sl++)=(( dest_g-(int)*sl)*fade_on/total_fades+*sl);
- *(sl++)=(( dest_b-(int)*sl)*fade_on/total_fades+*sl);
- }
- }
-